package com.game.modular.game.playerAssets.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.game.comment.exection.InfoTips;
import com.game.comment.exection.ServiceException;
import com.game.modular.game.battle.info.base.PvpPlayerInfo;
import com.game.modular.game.battle.panel.attribute.PlayerHeroAttributeServiceImpl;
import com.game.modular.game.battle.process.PlayerPvpServiceImpl;
import com.game.modular.game.battle.info.base.PvpPlayerInfoServiceImpl;
import com.game.modular.game.playerAssets.domain.PlayerBag;
import com.game.modular.game.playerAssets.domain.PlayerHero;
import com.game.modular.game.battle.panel.attribute.domain.PlayerHeroAttribute;
import com.game.modular.game.playerAssets.domain.PvpRanks;
import com.game.modular.game.playerAssets.mapper.PlayerHeroMapper;
import com.game.modular.game.playerAssets.service.base.PlayerHeroBaseServiceImpl;
import com.game.modular.game.playerMatch.service.PlayerMatchServiceImpl;
import com.game.modular.game.playerMatch.domain.PvpCity;
import com.game.modular.game.playerMatch.service.PvpCityServiceImpl;
import com.game.modular.game.playerMatch.service.PvpRanksServiceImpl;
import com.game.modular.gameCore.cultivate.domain.*;
import com.game.modular.gameCore.cultivate.service.impl.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

import static com.game.modular.game.playerAssets.domain.PlayerHero.recalculateAttributes;

/**
 * 游戏账户武将数据(PlayerHero)表服务实现类
 *
 * @author cxy
 * @since 2024-07-18 10:48:50
 */
@Slf4j
@Service
public class PlayerHeroServiceImpl extends PlayerHeroBaseServiceImpl {
    @Resource
    private PlayerHeroMapper playerHeroMapper;
    @Resource
    private CoreHeroServiceImpl coreWuJiangServiceImpl;
    @Resource
    private PvpCityServiceImpl pvpCityServiceImpl;
    @Resource
    private PlayerBagServiceImpl accountBagServiceImpl;
    @Resource
    private CoreHeroStarServiceImpl coreWuJiangStarServiceImpl;
    @Resource
    private CoreExperienceServiceImpl coreExperienceServiceImpl;
    @Resource
    private PvpRanksServiceImpl accountRanksServiceImpl;
    @Resource
    private CoreAccountConfigServiceImpl coreAccountConfigServiceImpl;
    @Resource
    private CoreHeroStarServiceImpl coreHeroStarServiceImpl;
    @Resource
    private CorePropServiceImpl corePropServiceImpl;
    @Resource
    private PlayerMatchServiceImpl playerMatchServiceImpl;
    @Resource
    private CoreSkillStarServiceImpl coreSkillStarServiceImpl;
    @Resource
    private PlayerSkillServiceImpl playerSkillServiceImpl;
    @Resource
    private PlayerHeroAttributeServiceImpl PlayerHeroAttributeServiceImpl;
    @Resource
    private PlayerPvpServiceImpl playerPvpServiceImpl;
    @Resource
    private PvpRanksServiceImpl pvpRanksServiceImpl;
    @Resource
    private PvpPlayerInfoServiceImpl pvpPlayerInfoServiceImpl;

    public void init(Long playerId) {
        List<PlayerHero> list = this.list(new LambdaQueryWrapper<PlayerHero>().eq(PlayerHero::getUid, playerId));
        log.info("开始缓存游戏账户武将数据数据");
        list.forEach(this::savaCache);
        log.info("游戏账户武将数据数据缓存成功,过期时间为60分钟,数据量{}",list.size());
    }

    public void registerInit(Long playerId) {
        CoreAccountConfig playerGiveaway = coreAccountConfigServiceImpl.getCache(1L);
        String prop = playerGiveaway.getHero();
        String[] props = prop.split(",");
        List<String> giftList = Arrays.asList(props);
        giftList.forEach(heroStr -> {
            String[] split = heroStr.split("&");
            Long heroId = Long.valueOf(split[0]);
            int value = Integer.parseInt(split[1]);
            obtainHero(playerId, heroId, value);
        });
    }
    public void updateMilitaryStrength(Map<Long, Long> update) {
        update.forEach((playerHeroId, currentForce) -> {
            PlayerHero playerHero = new PlayerHero();
            playerHero.setId(playerHeroId);
            playerHero.setCurrentForce(currentForce);
            updateById(playerHero);;
        });
    }
    public void updateRankOrder(Long playerId, Long heroId, int i) {
        PlayerHero playerHero = selectCache(playerId, heroId);
        if (playerHero!= null) {
            playerHero.setRankOrder(i);
            updateById(playerHero);
        }
    }

    public PlayerHero buBing(
            Long playerId,
            Long coreWuJiangId,
            Long troopsQuantity
    ) {
        Long currentMatchId = playerMatchServiceImpl.currentMatchId(playerId);
        PlayerHero playerHero = select(playerId, coreWuJiangId);
        if (playerHero == null) {
            throw new ServiceException("英雄不属于当前用户");
        }

        PvpRanks accountRanks = getWuJiangRanks(playerId, coreWuJiangId);
        if (accountRanks.getStatus() == 2) {
            throw new ServiceException("队伍在战斗无法补兵");
        }
        PvpCity pvpCity = pvpCityServiceImpl.getCache(
                currentMatchId, Math.toIntExact(accountRanks.getCityId()));
        long readyArmy = pvpCity.getReadyArmy();
        Long maxReadyArmy = (long) (playerHero.getDes() * 32);
        if (troopsQuantity > maxReadyArmy) {
            throw new ServiceException("补兵数量不能超过武将的统率能力上限");
        }
        // 计算增加的兵力
        long num = troopsQuantity - playerHero.getCurrentForce();
        if (num - readyArmy > 0) {
            throw new ServiceException("城池预备兵数量不足");
        }

        playerHero.setCurrentForce(troopsQuantity);
        pvpCity.setReadyArmy(readyArmy - num);
        this.updateById(playerHero);
        pvpCityServiceImpl.update(pvpCity);
        return playerHero;
    }

    private PvpRanks getWuJiangRanks(Long playerId, Long coreWuJiangId) {
        List<PvpRanks> collect = accountRanksServiceImpl.list(playerId).stream()
                .filter(item -> item.obtainCoreHeroIds().contains(coreWuJiangId))
                .collect(Collectors.toList());
        if (collect.isEmpty()) {
            throw new ServiceException("队伍不存在");
        }
        return collect.get(0);
    }

    public List<PlayerHero> buBing(Long playerId, int rankNo) {
        Long currentMatchId = playerMatchServiceImpl.currentMatchId(playerId);
        PvpRanks accountRanks = accountRanksServiceImpl.select(playerId, String.valueOf(rankNo));
        Long cityId = accountRanks.getCityId();
        if (cityId==0){
            throw new ServiceException("队伍未出战");
        }
        List<PlayerHero> ownerWuJiangList = accountRanksServiceImpl.getWuJiang(playerId, String.valueOf(rankNo));
        if (ownerWuJiangList.isEmpty()){
            throw new ServiceException("武将为空");
        }

        PvpCity pvpCity = pvpCityServiceImpl.getCache(currentMatchId, Math.toIntExact(cityId));
        long readyArmy = pvpCity.getReadyArmy();
        long averageReadyArmy = readyArmy / ownerWuJiangList.size();

        log.info("======================对局{},玩家{}队伍补充兵力============================", currentMatchId, playerId);
        for (PlayerHero playerHero : ownerWuJiangList) {
            Long maxCurrentForce = PlayerHero.getMaxCurrentForce(playerHero);
            Long currentForce = playerHero.getCurrentForce();

            long need = maxCurrentForce - currentForce;
            long cityReadyArmy = pvpCity.getReadyArmy();
            long reduce;

            synchronized (playerHero.getUid()) {
                if (cityReadyArmy >= need) { // 城池预备兵足够
                    playerHero.setCurrentForce(PlayerHero.getMaxCurrentForce(playerHero));
                    reduce = need;
                    pvpCity.setReadyArmy(cityReadyArmy - need);
                } else { // 城池预备兵不足
                    playerHero.setCurrentForce(averageReadyArmy);
                    reduce = averageReadyArmy - playerHero.getCurrentForce();
                    pvpCity.setReadyArmy(cityReadyArmy + reduce);
                }
                log.info("城池{},预备兵{}减少:{},武将{}",
                        pvpCity.getCoreCityId(), pvpCity.getReadyArmy(), reduce,
                        playerHero.getName() + playerHero.getCurrentForce()
                );
                this.updateById(playerHero);
            }
        }

        return accountRanksServiceImpl.getWuJiang(playerId, String.valueOf(rankNo));
    }

    public PlayerHero obtainHero(Long playerId, Long coreHeroId, Integer quantity) {
        PlayerHero accountHero = select(playerId, coreHeroId);
        CoreHero coreHero = coreWuJiangServiceImpl.getCache(coreHeroId);
        CoreHeroStar coreHeroStar = coreHeroStarServiceImpl.getCache(coreHeroId, 0);
        CoreSkillStar coreSkillStar = coreSkillStarServiceImpl.getCache(coreHero.getSkill(), 0);
        if (accountHero == null) {
            accountHero = new PlayerHero();
            accountHero.setUid(playerId);
            accountHero.setCoreHeroId(coreHeroId);
            accountHero.setLevel(1);
            accountHero.setStar(coreSkillStar.getSkillStar());
            // 查经验表
            CoreExperience coreExperience = coreExperienceServiceImpl.getCache(1, 1);
            accountHero.setNextExp(coreExperience.getExp());
            accountHero.setName(coreHero.getName());
            ////////
            accountHero.setSkill(coreSkillStar.getId());
            ////////
            recalculateAttributes(accountHero, coreHero,coreHeroStar);

            save(accountHero);
            quantity = quantity - 1;
            if (quantity > 0) {
                heroToProp(playerId, coreHeroId, quantity);
            }
        } else {
            // 转化为信物
            heroToProp(playerId, coreHeroId, 1);
            log.info("玩家{}武将{}已转化为信物", playerId, accountHero.getName());
        }
        return accountHero;
    }

    private void heroToProp(Long playerId, Long coreHeroId, Integer quantity) {
        String prop = coreHeroStarServiceImpl.getProp(coreHeroId);
        if (!prop.contains("&")) {
            throw new InfoTips("当前武将不存在信物");
        }
        Long propId = Long.valueOf(prop.split("&")[0]);
        // 添加物品
        accountBagServiceImpl.obtainBackpackItems(playerId, Long.valueOf(quantity), propId);
    }


    public PvpRanks clickBattle(
            Long playerId,
            Long matchId,
            Long rankNo,
            Long targetCityId
    ) {
        PvpRanks accountRanks = pvpRanksServiceImpl.select(playerId,rankNo);

        if (accountRanks == null) {
            throw new ServiceException("请先编队");
        }
        if (accountRanks.getHeroId1() == 0 && accountRanks.getHeroId2() == 0 && accountRanks.getHeroId3() == 0) {
            throw new ServiceException("队伍不能为空");
        }
        // 检验城池所属
        Long uid = accountRanks.getUid();
        Long cityId = accountRanks.getCityId();
        PvpPlayerInfo pvpPlayerInfo = pvpPlayerInfoServiceImpl.get(matchId, uid);
        Set<Long> currentCity = pvpPlayerInfo.getCurrentCity();
        if (!currentCity.contains(targetCityId)){
            throw new ServiceException("当前城池不属于当前用户");
        }
        // 更新
        accountRanks.setCityId(targetCityId);
        pvpRanksServiceImpl.updateBy(uid, rankNo, accountRanks);
        return accountRanks;
    }

    // 升星
    @Transactional
    public PlayerHero upgrade(Long uid, Long coreHeroId) {
        PlayerHero playerHero = select(uid, coreHeroId);
        if (playerHero == null) {
            throw new ServiceException("武将不存在");
        }
        if (playerHero.getStar() == 5) {
            return playerHero;
        }
        // 基础数据
        CoreHero coreHero = coreWuJiangServiceImpl.getCache(coreHeroId);
        // 获取消耗信息
        int nextStar = playerHero.getStar() + 1;
        CoreHeroStar nextWuJiangStar = coreWuJiangStarServiceImpl.getCache(coreHeroId, nextStar);

        Long propId = nextWuJiangStar.getPropId();
        Long propNum = nextWuJiangStar.getPropNum();

        // 消耗物品
        accountBagServiceImpl.use(uid, propNum, propId);
        // 武将升星 nextWuJiangStar
        playerHero.setStar(playerHero.getStar() + 1);
        CoreSkillStar cache = coreSkillStarServiceImpl.getCache(coreHero.getSkill(), playerHero.getStar());
        playerHero.setSkill(cache.getSkillId());
        recalculateAttributes(playerHero, coreHero, nextWuJiangStar);
        // 更新
        updateById(playerHero);
        return playerHero;
    }

    @Transactional
    public PlayerHero levelUp(
            Long uid,
            Long coreHeroId,
            Long corePropId,
            Long corePropNum
    ) {
        PlayerHero accountWuJiang = select(uid, coreHeroId);
        if (accountWuJiang == null) {
            throw new ServiceException("武将不存在");
        }
        // 查看背包经验道具
        if (accountWuJiang.getCurrentExp() < accountWuJiang.getNextExp()) {
            // 使用经验道具
            PlayerBag accountBag = accountBagServiceImpl.eqSelect(PlayerBag.builder().uid(uid).corePropId(corePropId).build());
            Long num = accountBag.getNum();
            if (num < corePropNum) {
                throw new ServiceException("道具不足");
            }
            accountBag.setNum(num - corePropNum);
            // 获取经验
            String useValue = corePropServiceImpl.getCache(corePropId).getUseValue();
            accountWuJiang.setCurrentExp(accountWuJiang.getCurrentExp() + Long.parseLong(useValue) * corePropNum);
        }

        // 基础数据
        CoreHero coreHero = accountWuJiang.getCoreHero();
        // 武将升级
        CoreExperience coreExperience = coreExperienceServiceImpl.getCache(
                accountWuJiang.getLevel() + 1, 1);
        // 获取成长属性
        CoreHeroStar coreHeroStar = coreWuJiangStarServiceImpl.getCache(
                accountWuJiang.getCoreHeroId(), accountWuJiang.getStar());
        PlayerHero res = PlayerHero.upgrade(accountWuJiang, coreHero, coreHeroStar, coreExperience);
        // 更新
        updateById(res);
        return res;
    }

    @Transactional
    public PlayerHero wearEquipment(
            Long uid,
            @NotNull(message = "武将id不能为空") Long coreHeroId,
            Long playerBagId
    ) {
        PlayerHero playerHero = select(uid, coreHeroId);
        // 使用物品
        PlayerBag accountBag = accountBagServiceImpl.useBagItem(uid, playerBagId,1L,playerHero.getId());
        // 计算穿戴
        PlayerHero equip = PlayerHero.equip(playerHero, accountBag);
        updateById(equip);
        return equip;
    }

    public PlayerHero unloadEquipment(
            Long uid,
            Long coreHeroId,
            Long playerBagId
    ) {
        PlayerHero playerHero = select(uid, coreHeroId);
        // 恢复物品
        PlayerBag playerBag = accountBagServiceImpl.backBagItem(uid, playerBagId,1L);
        // 计算穿戴
        PlayerHero equip = PlayerHero.unEquip(playerHero, playerBag);
        updateById(equip);
        return equip;
    }

    public PlayerHero wearSkill(
            Long uid,
            Long heroId,
            @NotNull(message = "卡槽位置不能为空")
            @Min(value = 1, message = "卡槽位置不能小于1")
            @Max(value = 2, message = "卡槽位置不能大于2")
            Integer skillSlot,
            @NotNull(message = "技能id不能为空") Long coreSkillStarId
    ) {
        PlayerHero playerHero = select(uid, heroId);
        Long skillSlot1 = playerHero.getSkillSlot1();
        Long skillSlot2 = playerHero.getSkillSlot2();
        if (skillSlot==1){
            if (skillSlot1 != 0) {
                throw new ServiceException("卡槽已满");
            }
            playerHero.setSkillSlot1(coreSkillStarId);
            playerSkillServiceImpl.occupySkill(uid, coreSkillStarId);
            updateById(playerHero);
            playerHero = select(uid, heroId);
        }
        if (skillSlot==2){
            if (skillSlot2 != 0) {
                throw new ServiceException("卡槽已满");
            }
            playerHero.setSkillSlot2(coreSkillStarId);
            playerSkillServiceImpl.occupySkill(uid, coreSkillStarId);
            updateById(playerHero);
            playerHero = select(uid, heroId);
        }
        return playerHero;
    }

    public PlayerHero unloadSkill(
            Long uid,
            Long heroId,
            @NotNull(message = "卡槽位置不能为空")
            @Min(value = 1, message = "卡槽位置不能小于1")
            @Max(value = 2, message = "卡槽位置不能大于2")
            Integer skillSlot,
            @NotNull(message = "技能id不能为空") Long coreSkillStarId
    ) {
        PlayerHero playerHero = select(uid, heroId);
        Long skillSlot1 = playerHero.getSkillSlot1();
        Long skillSlot2 = playerHero.getSkillSlot2();
        if (skillSlot==1){
            if (skillSlot1 == 0) {
                throw new ServiceException("卡槽不存在技能");
            }
            playerHero.setSkillSlot1(0L);
            playerSkillServiceImpl.unOccupySkill(uid, coreSkillStarId);
            updateById(playerHero);
            playerHero = select(uid, heroId);
        }
        if (skillSlot==2){
            if (skillSlot2 != 0) {
                throw new ServiceException("卡槽不存在技能");
            }
            playerHero.setSkillSlot2(0L);
            playerSkillServiceImpl.unOccupySkill(uid, coreSkillStarId);
            updateById(playerHero);
            playerHero = select(uid, heroId);
        }
        return playerHero;
    }

    public Set<Long> getDeadSet(Long battleId, List<PlayerHero> targetRange) {
        return targetRange.stream()
                .map(item -> PlayerHeroAttributeServiceImpl.selectCache(battleId, item.getId()))
                .filter(item -> item.getCurrentForce() <= 0)
                .mapToLong(PlayerHeroAttribute::getId)
                .boxed()
                .collect(Collectors.toSet());
    }
    public Set<Long> getSurvivalSet(Long battleId, List<PlayerHero> targetRange) {
        return targetRange.stream()
                .map(item -> PlayerHeroAttributeServiceImpl.selectCache(battleId, item.getId()))
                .filter(item -> item.getCurrentForce() > 0)
                .mapToLong(PlayerHeroAttribute::getId)
                .boxed()
                .collect(Collectors.toSet());
    }
}